using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Timers;
using Gameplay.PVE.Utils;
using UnityEditor;
using UnityEngine;

namespace Gameplay.PVE.Editor
{
    /// <summary>
    /// 时间线数据结构
    /// </summary>
    public struct TimeDataStr
    {
        /// <summary>
        /// 技能是否再关闭状态
        /// </summary>
        public bool isSkillOver;

        /// <summary>
        /// 开始帧
        /// </summary>
        public int startFrame;

        /// <summary>
        /// 结束帧
        /// </summary>
        public int endFrame;

        /// <summary>
        /// 时间轴名称
        /// </summary>
        public string name;

        /// <summary>
        /// 是否无限帧
        /// </summary>
        public bool forever;

        /// <summary>
        /// 事件点集合
        /// </summary>
        public int[] eventFrame;
    }
    
    /// <summary>
    /// 功能函数静态类
    /// </summary>
    public static class Common
    {

        /// <summary>
        /// 相对坐标对象，动画对象
        /// </summary>
        public const string TARGET_ACTION = "actionTarget";

        /// <summary>
        /// 相对坐标对象，场景对象
        /// </summary>
        public const string TARGET_SCENE = "scene_target";

        /// <summary>
        /// 相对坐标对象，敌人对象
        /// </summary>
        public const string TARGET_FOE = "scene_foe";

        /// <summary>
        /// 客户端坐标对象，无对象，只有坐标
        /// </summary>
        public const string TARGET_CLIENT = "clientTarget";

        public static Color DefaultBackgroundColor = new Color(0.76f, 0.76f, 0.76f, 0);


        static Common()
        {

#if UNITY_EDITOR
            colorBlockStyle.normal.background = EditorGUIUtility.whiteTexture;
#endif

            colorBlockStyle.stretchWidth = true;
            colorBlockStyle.alignment = TextAnchor.MiddleLeft;
        }


        /// <summary>
        /// 编辑器列表默认样式
        /// </summary>
        public static GUIStyle colorBlockStyle = new GUIStyle();

        /// <summary>
        /// 画一个横向列表条目
        /// </summary>
        /// <param name="position">坐标</param>
        /// <param name="text">文本</param>
        /// <param name="bgColor">背景色</param>
        /// <param name="selected">是否选中</param>
        /// <param name="fontStyle">字体样式</param>
        /// <param name="fontSize">字体大小</param>
        public static void DrawColorBox(Rect position, string text, Color bgColor, bool selected = false, FontStyle fontStyle = FontStyle.Normal, int fontSize = 12)
        {
            // init style;
            colorBlockStyle.fontStyle = fontStyle;
            colorBlockStyle.fontSize = fontSize;
            colorBlockStyle.clipping = TextClipping.Clip;


            if (Event.current.type == EventType.Repaint)
            {
                var orgColor = GUI.color;
                GUI.color = bgColor;
                colorBlockStyle.Draw(position, text, false, false, selected, false);
                GUI.color = orgColor;
            }
        }

        /// <summary>
        /// 画一个横向列表条目
        /// </summary>
        /// <param name="position">坐标</param>
        /// <param name="text">文本</param>
        /// <param name="bgColor">背景色</param>
        /// <param name="fontColor">字色</param>
        /// <param name="selected">是否选中</param>
        /// <param name="fontStyle">字体样式</param>
        /// <param name="fontSize">字体大小</param>
        public static void DrawColorBox(Rect position, string text, Color bgColor, Color fontColor, bool selected = false, FontStyle fontStyle = FontStyle.Normal, int fontSize = 12)
        {
            var orgFontColor = colorBlockStyle.normal.textColor;

            colorBlockStyle.normal.textColor = fontColor;
            DrawColorBox(position, text, bgColor, selected, fontStyle, fontSize);
            colorBlockStyle.normal.textColor = orgFontColor;
        }

        /// <summary>
        /// 根据名字获取go的子节点，该查找方法通过一次获取到所有子物体，遍历比对获取目标子节点
        /// </summary>
        /// <param name="go">对象</param>
        /// <param name="childName">子物体名称</param>
        /// <returns>子物体对象</returns>
        public static Transform GetChildTransByName(GameObject go, string childName)
        {
            Transform childTrans = null;
            Transform[] trans = go.GetComponentsInChildren<Transform>();
            for (int i = 0; i < trans.Length; i++)
            {
                if (trans[i].name == childName)
                {
                    childTrans = trans[i];
                    break;
                }
            }
            return childTrans;
        }

        /// <summary>
        /// 根据名字获取go的子节点，该查找方法通过逐层遍历go的子物体，来查找go的名为name的子节点
        /// </summary>
        /// <param name="go">对象</param>
        /// <param name="name">子物体名称</param>
        /// <returns>子物体对象</returns>
        public static Transform GetChildByName(GameObject go, string name)
        {
            if (go == null || string.IsNullOrEmpty(name))
            {
                return null;
            }
            List<Transform> gos = new List<Transform>();
            gos.Add(go.transform);
            return GetChildByNameHelp(gos, name);
        }
        static Transform GetChildByNameHelp(List<Transform> gos, string name)
        {
            if (gos.Count == 0)
                return null;

            for (int i = 0; i < gos.Count; i++)
            {
                if (gos[i].name == name)
                {
                    return gos[i];

                }
            }

            List<Transform> childGos = new List<Transform>();
            for (int i = 0; i < gos.Count; i++)
            {
                if (gos[i].childCount > 0)
                {
                    for (int j = 0; j < gos[i].childCount; j++)
                    {
                        childGos.Add(gos[i].GetChild(j));
                    }
                }
            }

            return GetChildByNameHelp(childGos, name);



        }

        /// <summary>
        /// 在指定时间过后执行指定的表达式
        /// </summary>
        /// <param name="interval">事件之间经过的时间（以毫秒为单位）</param>
        /// <param name="action">要执行的表达式</param>
        /// <returns>返回Timer对象</returns>
        public static Timer SetTimeout(double interval, Action action)
        {
            Timer timer = new Timer(interval);
            timer.Elapsed += delegate (object sender, ElapsedEventArgs e)
           {
               timer.Enabled = false;
               action();
           };
            timer.Enabled = true;

            return timer;
        }


        /// <summary>
        /// 由慢变快变慢
        /// </summary>
        /// <param name="start">开始值</param>
        /// <param name="end">结束值</param>
        /// <param name="value">0-1过程</param>
        /// <returns>当前值</returns>
        public static float Hermite(float start, float end, float value)
        {
            return Mathf.Lerp(start, end, value * value * (3.0f - 2.0f * value));
        }


        /// <summary>
        /// 由快变慢
        /// </summary>
        /// <param name="start">开始值</param>
        /// <param name="end">结束值</param>
        /// <param name="value">0-1过程</param>
        /// <returns>当前值</returns>
        public static float Sinerp(float start, float end, float value)
        {
            return Mathf.Lerp(start, end, Mathf.Sin(value * Mathf.PI * 0.5f));
        }

        /// <summary>
        /// 由慢变快
        /// </summary>
        /// <param name="start">开始值</param>
        /// <param name="end">结束值</param>
        /// <param name="value">0-1过程</param>
        /// <returns>当前值</returns>
        public static float Coserp(float start, float end, float value)
        {
            return Mathf.Lerp(start, end, 1.0f - Mathf.Cos(value * Mathf.PI * 0.5f));
        }

        /// <summary>
        /// 获取当前组件播放帧数
        /// </summary>
        /// <param name="data">时间线数据结构</param>
        /// <param name="worldFrame">世界帧数</param>
        /// <returns>-1为不在生命周期内</returns>
        public static int GetPluginFrame(TimeDataStr data, int worldFrame)
        {
            if (data.startFrame <= worldFrame && (data.endFrame >= worldFrame || data.forever))
            {
                return worldFrame - data.startFrame;
            }

            return -1;
        }

        /// <summary>
        /// 获取时间轴整体播放时间
        /// </summary>
        /// <param name="data">时间线数据结构</param>
        /// <returns>时间（秒）</returns>
        public static float GetFrameAllTime(TimeDataStr data)
        {
            float time = (data.endFrame - data.startFrame) * Common.FrameToTimelineValue(1);

            return time;
        }


        /// <summary>
        /// 回弹效果
        /// </summary>
        /// <param name="start">开始值</param>
        /// <param name="end">结束值</param>
        /// <param name="value">0-1过程</param>
        /// <returns>当前值</returns>
        public static float Berp(float start, float end, float value)
        {
            value = Mathf.Clamp01(value);
            value = (Mathf.Sin(value * Mathf.PI * (0.2f + 2.5f * value * value * value)) * Mathf.Pow(1f - value, 2.2f) + value) * (1f + (1.2f * (1f - value)));
            return start + (end - start) * value;
        }


        /// <summary>
        /// 获取组件事件点
        /// </summary>
        /// <param name="frame">组件相对帧</param>
        /// <param name="data">时间线数据结构</param>
        /// <returns>-1 为没有触发事件点，否则返回时间点的帧位置</returns>
        public static int GetPluginEventFrame(int frame, TimeDataStr data)
        {
            for (int i = 0; i < data.eventFrame.Length; i++)
            {
                if (data.eventFrame[i] == frame)
                {
                    return frame;
                }
            }

            return -1;
        }


        /// <summary>
        /// 获取组件事件点
        /// </summary>
        /// <param name="frame">世界帧</param>
        /// <param name="data">时间线数据结构</param>
        /// <returns>-1 为没有触发事件点，否则返回时间点的帧位置</returns>
        public static int GetPluginEventFrameWorld(int worldFrame, TimeDataStr data)
        {
            var frame = GetPluginFrame(data, worldFrame);

            if (frame == -1)
            {
                return -1;
            }

            for (int i = 0; i < data.eventFrame.Length; i++)
            {
                if (data.eventFrame[i] == frame)
                {
                    return frame;
                }
            }

            return -1;
        }

        /// <summary>
        /// 计算帧的时间
        /// </summary>
        /// <param name="frame">帧数</param>
        /// <returns>帧数所需要的时间（秒）</returns>
        public static float FrameToTimelineValue(float frame, float speed = 1)
        {
            return (float)frame / (PveUtils.fps * speed);
        }
        

        
        /// <summary>
        /// 自定义打印错误日志方法
        /// </summary>
        /// <param name="info">日志内容</param>
        [System.Diagnostics.Conditional("DEBUG")]
        public static void LogError(string info)
        {
            if (Debug.unityLogger.logEnabled)
            {
                Debug.LogWarning(string.Format("[Skills Editor] {0}", info));
            }
        }


        /// <summary>
        /// 获取Resources相对地址
        /// </summary>
        /// <param name="valueUrl">原始地址</param>
        /// <param name="isExt">是否保留扩展名</param>
        /// <param name="resourcesName">选对目录名称</param>
        /// <returns>相对地址</returns>
        public static string GetUrlResources(string valueUrl, bool isExt = false, string resourcesName = "Resources")
        {
            string[] arr = valueUrl.Split('/');
            string url = "";
            for (int i = arr.Length - 1; i > -1; i--)
            {
                if (arr[i] != resourcesName)
                {
                    if (url.Length > 0)
                    {
                        url = arr[i] + "/" + url;
                    }
                    else
                    {
                        if (isExt)
                        {
                            url = arr[i];
                        }
                        else
                        {
                            url = arr[i].Split('.')[0];
                        }

                    }

                }
                else
                {
                    break;
                }

            }

            return url;
        }

        /// <summary>
        /// 根据GameObject的位置和朝向，将世界坐标位置转换为先对与他的局部坐标
        /// </summary>
        /// <param name="target">相对的对象</param>
        /// <param name="worldPos">世界坐标</param>
        /// <returns>相对的局部坐标</returns>
        public static Vector3 GameObjectRelativeLocalPositon(GameObject target, Vector3 worldPos)
        {
            if (target == null)
            {
                return worldPos;
            }

            var tf = target.transform;

            return RelativeLocalPositon(tf.position, tf.rotation, worldPos);
        }

        /// <summary>
        /// 根据目标的位置和朝向，将世界坐标位置转换为先对与他的局部坐标
        /// </summary>
        /// <param name="targetPositon">目标的位置</param>
        /// <param name="targetRotation">目标的朝向</param>
        /// <param name="worldPos">世界坐标</param>
        /// <returns>相对的局部坐标</returns>
        public static Vector3 RelativeLocalPositon(Vector3 targetPositon, Quaternion targetRotation, Vector3 worldPos)
        {

            Vector3 v3 = worldPos - targetPositon;

            return Quaternion.Inverse(targetRotation) * v3;

        }


        /// <summary>
        /// 根据GameObject的位置和朝向，偏移后的世界坐标位置
        /// </summary>
        /// <param name="target">相对的对象</param>
        /// <param name="localPos">局部偏移的坐标</param>
        /// <returns>偏移后的世界坐标</returns>
        public static Vector3 GameObjectRelativeWorldPosition(GameObject target, Vector3 localPos)
        {
            if (target == null)
            {
                return localPos;
            }

            var tf = target.transform;

            return RelativeWorldPosition(tf.position, tf.rotation, localPos);
        }

        /// <summary>
        /// 根据目标的位置和朝向，偏移后的世界坐标位置
        /// </summary>
        /// <param name="targetPositon">目标的位置</param>
        /// <param name="targetRotation">目标的朝向</param>
        /// <param name="localPos">局部偏移的坐标</param>
        /// <returns>偏移后的世界坐标</returns>
        public static Vector3 RelativeWorldPosition(Vector3 targetPositon, Quaternion targetRotation, Vector3 localPos)
        {

            return targetPositon + targetRotation * localPos;
        }


        /// <summary>
        /// 根据路径获取资源名称
        /// </summary>
        /// <param name="valueUrl">资源加载地址</param>
        /// <param name="isExt">是否需要扩展名</param>
        /// <returns>资源文件名</returns>
        public static string GetUrlResouresName(string valueUrl, bool isExt = false)
        {
            string[] arr = valueUrl.Split('/');

            if (isExt)
            {
                return arr[arr.Length - 1];
            }
            else
            {
                return arr[arr.Length - 1].Split('.')[0];
            }
        }

        /// <summary>
        /// 更改对象和所有子对象的layer
        /// </summary>
        /// <param name="obj">设置对象</param>
        /// <param name="layer">layer层</param>
        public static void SetLayerOnAll(GameObject obj, int layer)
        {
            if (null == obj)
                return;

            foreach (Transform trans in obj.GetComponentsInChildren<Transform>(true))
            {
                trans.gameObject.layer = layer;
            }

        }


        /// <summary>
        /// 更改对象和所有子对象的layer
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="tag">tag 名称</param>
        public static void SetTagOnAll(GameObject obj, string tag)
        {
            if (null == obj || tag == null)
                return;

            foreach (Transform trans in obj.GetComponentsInChildren<Transform>(true))
            {
                trans.gameObject.tag = tag;
            }

        }

        /// <summary>
        /// 判断一个点是否在复杂平面多边形里面
        /// </summary>
        /// <param name="checkPoint">点</param>
        /// <param name="polygonPoints">平面的多个顶点</param>
        /// <returns>是否在平面上</returns>
        public static bool IsInPolygon(Vector2 checkPoint, Vector2[] polygonPoints)
        {
            int counter = 0;
            int i;
            float xinters;
            Vector2 p1, p2;
            var pointCount = polygonPoints.Length;
            p1 = polygonPoints[0];

            for (i = 1; i <= pointCount; i++)
            {
                p2 = polygonPoints[i % pointCount];
                if (
                    checkPoint.x > Math.Min(p1.x, p2.x) &&
                    checkPoint.x <= Math.Max(p1.x, p2.x)
                )
                {
                    if (checkPoint.y <= Math.Max(p1.y, p2.y))
                    {
                        if (p1.x != p2.x)
                        {
                            xinters =
                                (checkPoint.x - p1.x) *
                                    (p2.y - p1.y) /
                                    (p2.x - p1.x) +
                                p1[1];
                            if (p1[1] == p2[1] || checkPoint[1] <= xinters)
                            {
                                counter++;
                            }
                        }
                    }
                }
                p1 = p2;
            }
            if (counter % 2 == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 保存base64格式
        /// </summary>
        /// <param name="str">文本</param>
        /// <returns>base64文本</returns>
        public static string SkillDataJsonToBase64(string json)
        {
            return EncodeBase64("utf-8", json);
        }

        /// <summary>
        /// 解析base64
        /// </summary>
        /// <param name="base64">base64文本</param>
        /// <returns>文本</returns>
        public static string SkillDataBase64ToJson(string base64)
        {
            return DecodeBase64("utf-8", base64);
        }

        /// <summary>
        /// 文本压缩，并base64编码
        /// </summary>
        /// <param name="code_type">文本编码</param>
        /// <param name="code">文本</param>
        /// <returns>base64文本</returns>
        public static string EncodeBase64(string code_type, string code)
        {
            string encode = "";
            byte[] bytes = GZIPCompress(Encoding.GetEncoding(code_type).GetBytes(code));
            try
            {
                encode = Convert.ToBase64String(bytes);
            }
            catch
            {
                encode = code;
            }
            return encode;
        }
        /// <summary>
        /// base64解码，解压缩
        /// </summary>
        /// <param name="code_type">文本编码</param>
        /// <param name="code">base64文本</param>
        /// <returns>文本</returns>
        public static string DecodeBase64(string code_type, string code)
        {

            string decode = "";
            byte[] bytes = GZIPDecompress(Convert.FromBase64String(code));

            try
            {
                decode = Encoding.GetEncoding(code_type).GetString(bytes);
            }
            catch
            {
                decode = code;
            }



            return decode;
        }

        /// <summary>
        /// 二进制，压缩，转换base64文本
        /// </summary>
        /// <param name="data">二进制</param>
        /// <returns>base64文本</returns>
        public static string ByteToBase64(byte[] data)
        {
            return Convert.ToBase64String(GZIPCompress(data));
        }

        /// <summary>
        /// base64文本，转换二进制，解压
        /// </summary>
        /// <param name="data">base64文本</param>
        /// <returns>二进制</returns>
        public static Byte[] Base64ToByte(string data)
        {
            return GZIPDecompress(Convert.FromBase64String(data));
        }

        /// <summary>
        /// 对象序列化
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns>序列化后二进制</returns>
        public static byte[] SerializeObject(object obj)
        {
            if (obj == null)
                return null;
            //内存实例
            MemoryStream ms = new MemoryStream();
            //创建序列化的实例
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);//序列化对象，写入ms流中  
            byte[] bytes = ms.GetBuffer();
            return bytes;
        }

        /// <summary>
        /// 对象反序列化
        /// </summary>
        /// <param name="bytes">序列化后二进制</param>
        /// <returns>对象</returns>
        public static object DeserializeObject(byte[] bytes)
        {
            object obj = null;
            if (bytes == null)
                return obj;
            //利用传来的byte[]创建一个内存流
            MemoryStream ms = new MemoryStream(bytes);
            ms.Position = 0;
            BinaryFormatter formatter = new BinaryFormatter();
            obj = formatter.Deserialize(ms);//把内存流反序列成对象  
            ms.Close();
            return obj;
        }

        /// <summary>
        /// GZip压缩
        /// </summary>
        /// <param name="rawData">二进制</param>
        /// <returns>压缩后的二进制</returns>
        public static byte[] GZIPCompress(byte[] rawData)
        {
            MemoryStream ms = new MemoryStream();
            GZipStream compressedzipStream = new GZipStream(ms, CompressionMode.Compress, true);
            compressedzipStream.Write(rawData, 0, rawData.Length);
            compressedzipStream.Close();
            return ms.ToArray();
        }

        /// <summary>
        /// GZip解压
        /// </summary>
        /// <param name="zippedData">压缩过的二进制</param>
        /// <returns>原始二进制</returns>
        public static byte[] GZIPDecompress(byte[] zippedData)
        {
            MemoryStream ms = new MemoryStream(zippedData);
            GZipStream compressedzipStream = new GZipStream(ms, CompressionMode.Decompress);
            MemoryStream outBuffer = new MemoryStream();
            byte[] block = new byte[1024];
            while (true)
            {
                int bytesRead = compressedzipStream.Read(block, 0, block.Length);
                if (bytesRead <= 0)
                    break;
                else
                    outBuffer.Write(block, 0, bytesRead);
            }
            compressedzipStream.Close();
            return outBuffer.ToArray();
        }
    }
    /// <summary>
    /// 界面颜色类
    /// </summary>
    public class ActionColorSet
    {
        /// <summary>
        /// 默认颜色
        /// </summary>
        public static Color normal = Color.gray * 1.5f;
        /// <summary>
        /// 默认选中色
        /// </summary>
        public static Color normalSelected = Color.yellow;

        /// <summary>
        /// 预览颜色
        /// </summary>
        public static Color preview = Color.yellow * 0.6f;
        /// <summary>
        /// 预览选中色
        /// </summary>
        public static Color previewSelected = Color.yellow;
        /// <summary>
        /// 禁用颜色
        /// </summary>
        public static Color disabled = Color.gray * 0.5f;
        /// <summary>
        /// 禁用选中色
        /// </summary>
        public static Color disabledSelected = Color.red * 0.5f;

    }

    /// <summary>
    /// 时间线条颜色
    /// </summary>
    public class ActionColorFrameBar : ActionColorSet
    {

        public ActionColorFrameBar(string type = null)
        {

            normal = new Color(0, 179f / 255f, 140f / 255f);

        }

    }
}